package system

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/flipped-aurora/gin-vue-admin/server/global"
	"github.com/flipped-aurora/gin-vue-admin/server/model/system"
	systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
	"github.com/google/uuid"
	"time"
)

type Seckill_activity_deviceService struct{}

// CreateSeckill_activity_device 创建秒杀活动设备记录
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) CreateSeckill_activity_device(ctx context.Context, seckill_activity_device *system.Seckill_activity_device) (err error) {
	err = global.GVA_DB.Create(seckill_activity_device).Error
	return err
}

// DeleteSeckill_activity_device 删除秒杀活动设备记录
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) DeleteSeckill_activity_device(ctx context.Context, ID string) (err error) {
	err = global.GVA_DB.Delete(&system.Seckill_activity_device{}, "id = ?", ID).Error
	return err
}

// DeleteSeckill_activity_deviceByIds 批量删除秒杀活动设备记录
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) DeleteSeckill_activity_deviceByIds(ctx context.Context, IDs []string) (err error) {
	err = global.GVA_DB.Delete(&[]system.Seckill_activity_device{}, "id in ?", IDs).Error
	return err
}

// UpdateSeckill_activity_device 更新秒杀活动设备记录
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) UpdateSeckill_activity_device(ctx context.Context, seckill_activity_device system.Seckill_activity_device) (err error) {
	err = global.GVA_DB.Model(&system.Seckill_activity_device{}).Where("id = ?", seckill_activity_device.ID).Updates(&seckill_activity_device).Error
	return err
}

// GetSeckill_activity_device 根据ID获取秒杀活动设备记录
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) GetSeckill_activity_device(ctx context.Context, ID string) (seckill_activity_device system.Seckill_activity_device, err error) {
	err = global.GVA_DB.Where("id = ?", ID).First(&seckill_activity_device).Error
	return
}

// GetSeckill_activity_deviceInfoList 分页获取秒杀活动设备记录
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) GetSeckill_activity_deviceInfoList(ctx context.Context, info systemReq.Seckill_activity_deviceSearch) (list []system.Seckill_activity_device, total int64, err error) {
	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)
	// 创建db
	db := global.GVA_DB.Model(&system.Seckill_activity_device{})
	var seckill_activity_devices []system.Seckill_activity_device
	// 如果有条件搜索 下方会自动创建搜索语句
	if len(info.CreatedAtRange) == 2 {
		db = db.Where("created_at BETWEEN ? AND ?", info.CreatedAtRange[0], info.CreatedAtRange[1])
	}

	err = db.Count(&total).Error
	if err != nil {
		return
	}

	if limit != 0 {
		db = db.Limit(limit).Offset(offset)
	}

	err = db.Find(&seckill_activity_devices).Error
	return seckill_activity_devices, total, err
}
func (seckill_activity_deviceService *Seckill_activity_deviceService) GetSeckill_activity_devicePublic(ctx context.Context) {
	// 此方法为获取数据源定义的数据
	// 请自行实现
}

// UpdateStockSaga 发起Saga，前端编辑库存时用
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) UpdateStockSaga(ctx context.Context, req systemReq.UpdateStockSagaRequest) (err error) {
	// 1. 获取当前活动设备信息
	var activityDevice system.Seckill_activity_device
	err = global.GVA_DB.Where("id = ?", req.Activity_device_id).First(&activityDevice).Error
	if err != nil {
		return fmt.Errorf("获取活动设备信息失败: %w", err)
	}

	// 2. 计算库存差值（新库存 - 旧库存）
	oldStock := 0
	if activityDevice.Stock != nil {
		oldStock = *activityDevice.Stock
	}
	stockDiff := req.Stock - oldStock

	// 如果库存没有变化，直接返回
	if stockDiff == 0 {
		return nil
	}

	// 3. 开始事务
	tx := global.GVA_DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 4. 步骤1：扣减真实库存（decimal_device表）
	var decimalDevice system.Decimal_device
	err = tx.Where("id = ?", activityDevice.Seckill_decimal_device_id).First(&decimalDevice).Error
	if err != nil {
		tx.Rollback()
		return fmt.Errorf("获取设备信息失败: %w", err)
	}

	// 检查真实库存是否足够
	if decimalDevice.Stock == nil {
		tx.Rollback()
		return errors.New("设备真实库存为空")
	}

	// 如果是增加库存，检查真实库存是否足够
	if stockDiff > 0 {
		if *decimalDevice.Stock < stockDiff {
			tx.Rollback()
			return errors.New("设备真实库存不足")
		}
		// 扣减真实库存
		newStock := *decimalDevice.Stock - stockDiff
		err = tx.Model(&system.Decimal_device{}).Where("id = ?", activityDevice.Seckill_decimal_device_id).Update("stock", newStock).Error
		if err != nil {
			tx.Rollback()
			return fmt.Errorf("扣减真实库存失败: %w", err)
		}
	} else {
		// 如果是减少库存，恢复真实库存
		newStock := *decimalDevice.Stock - stockDiff // stockDiff是负数，所以是加
		err = tx.Model(&system.Decimal_device{}).Where("id = ?", activityDevice.Seckill_decimal_device_id).Update("stock", newStock).Error
		if err != nil {
			tx.Rollback()
			return fmt.Errorf("恢复真实库存失败: %w", err)
		}
	}

	// 5. 步骤2：更新活动库存（seckill_activity_device表）
	err = tx.Model(&system.Seckill_activity_device{}).Where("id = ?", req.Activity_device_id).Update("stock", req.Stock).Error
	if err != nil {
		tx.Rollback()
		return fmt.Errorf("更新活动库存失败: %w", err)
	}

	// 6. 提交事务
	err = tx.Commit().Error
	if err != nil {
		return fmt.Errorf("提交事务失败: %w", err)
	}

	return nil
}

// DecreaseStock Saga步骤1，扣减真实库存
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) DecreaseStock(ctx context.Context, req systemReq.DecreaseStockRequest) (err error) {
	// 获取活动设备信息
	var activityDevice system.Seckill_activity_device
	err = global.GVA_DB.Where("id = ?", req.Activity_device_id).First(&activityDevice).Error
	if err != nil {
		return fmt.Errorf("获取活动设备信息失败: %w", err)
	}

	// 扣减真实库存
	err = global.GVA_DB.Model(&system.Decimal_device{}).
		Where("id = ? AND stock >= ?", activityDevice.Seckill_decimal_device_id, req.Stock).
		Update("stock", global.GVA_DB.Raw("stock - ?", req.Stock)).Error
	if err != nil {
		return fmt.Errorf("扣减真实库存失败: %w", err)
	}

	return nil
}

// DecreaseStockCompensate Saga步骤1补偿
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) DecreaseStockCompensate(ctx context.Context, req systemReq.DecreaseStockRequest) (err error) {
	// 获取活动设备信息
	var activityDevice system.Seckill_activity_device
	err = global.GVA_DB.Where("id = ?", req.Activity_device_id).First(&activityDevice).Error
	if err != nil {
		return fmt.Errorf("获取活动设备信息失败: %w", err)
	}

	// 恢复真实库存
	err = global.GVA_DB.Model(&system.Decimal_device{}).
		Where("id = ?", activityDevice.Seckill_decimal_device_id).
		Update("stock", global.GVA_DB.Raw("stock + ?", req.Stock)).Error
	if err != nil {
		return fmt.Errorf("恢复真实库存失败: %w", err)
	}

	return nil
}

// UpdateStock Saga步骤2，更新活动库存
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) UpdateStock(ctx context.Context, req systemReq.UpdateStockRequest) (err error) {
	// 更新活动库存
	err = global.GVA_DB.Model(&system.Seckill_activity_device{}).
		Where("id = ?", req.Activity_device_id).
		Update("stock", req.Stock).Error
	if err != nil {
		return fmt.Errorf("更新活动库存失败: %w", err)
	}

	return nil
}

// UpdateStockCompensate Saga步骤2补偿
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) UpdateStockCompensate(ctx context.Context, req systemReq.UpdateStockRequest) (err error) {
	// 获取原始库存
	var activityDevice system.Seckill_activity_device
	err = global.GVA_DB.Where("id = ?", req.Activity_device_id).First(&activityDevice).Error
	if err != nil {
		return fmt.Errorf("获取活动设备信息失败: %w", err)
	}

	// 恢复原始库存（这里需要记录原始值，简化处理）
	// 实际项目中应该在事务中记录原始值
	err = global.GVA_DB.Model(&system.Seckill_activity_device{}).
		Where("id = ?", req.Activity_device_id).
		Update("stock", activityDevice.Stock).Error
	if err != nil {
		return fmt.Errorf("恢复活动库存失败: %w", err)
	}

	return nil
}

// PreheatStock 前端“预热”按钮用
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) PreheatStock(ctx context.Context, req systemReq.PreheatStockRequest) (err error) {
	// 1. 获取活动设备信息
	var activityDevice system.Seckill_activity_device
	err = global.GVA_DB.Where("id = ?", req.Activity_device_id).First(&activityDevice).Error
	if err != nil {
		return fmt.Errorf("获取活动设备信息失败: %w", err)
	}

	// 2. 检查库存是否为空
	if activityDevice.Stock == nil || *activityDevice.Stock <= 0 {
		return errors.New("库存为空，无法预热")
	}

	// 3. 预热Redis库存
	redisKey := fmt.Sprintf("seckill:stock:%d", req.Activity_device_id)

	// 清空之前的库存
	err = global.GVA_REDIS.Del(ctx, redisKey).Err()
	if err != nil {
		return fmt.Errorf("清空Redis库存失败: %w", err)
	}

	// 将库存数据推入Redis List
	for i := 0; i < *activityDevice.Stock; i++ {
		err = global.GVA_REDIS.LPush(ctx, redisKey, "1").Err()
		if err != nil {
			return fmt.Errorf("预热Redis库存失败: %w", err)
		}
	}

	// 设置过期时间（比如24小时）
	err = global.GVA_REDIS.Expire(ctx, redisKey, 24*60*60*time.Second).Err()
	if err != nil {
		return fmt.Errorf("设置Redis过期时间失败: %w", err)
	}

	return nil
}

// ClearRedis 补偿或手动清空Redis
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) ClearRedis(ctx context.Context, req systemReq.ClearRedisRequest) (err error) {
	// 清空相关Redis缓存
	pattern := "seckill:stock:*"
	keys, err := global.GVA_REDIS.Keys(ctx, pattern).Result()
	if err != nil {
		return fmt.Errorf("获取Redis键失败: %w", err)
	}

	if len(keys) > 0 {
		err = global.GVA_REDIS.Del(ctx, keys...).Err()
		if err != nil {
			return fmt.Errorf("清空Redis缓存失败: %w", err)
		}
	}

	return nil
}

// CacheAllToRedis 缓存列表
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) CacheAllToRedis(ctx context.Context) error {
	var list []system.Seckill_activity_device
	err := global.GVA_DB.Find(&list).Error
	if err != nil {
		return err
	}
	redisKey := "seckill:device:list"
	fields := make(map[string]string)
	for _, device := range list {
		id := fmt.Sprintf("%d", device.ID)
		value, _ := json.Marshal(device)
		fields[id] = string(value)
	}
	return global.GVA_REDIS.HMSet(ctx, redisKey, fields).Err()
}

// GetAllFromRedis 获取缓存列表数据
// Author [yourname](https://github.com/yourname)
func (seckill_activity_deviceService *Seckill_activity_deviceService) GetAllFromRedis(ctx context.Context) ([]system.Seckill_activity_device, error) {
	redisKey := "seckill:device:list"
	data, err := global.GVA_REDIS.HGetAll(ctx, redisKey).Result()
	if err != nil {
		return nil, err
	}
	var list []system.Seckill_activity_device
	for _, v := range data {
		var device system.Seckill_activity_device
		if err := json.Unmarshal([]byte(v), &device); err == nil {
			list = append(list, device)
		}
	}
	return list, nil
}

// SeckillCreateOrder 生成订单

// 辅助函数
func ptrString(s string) *string { return &s }
func ptrInt(i int) *int          { return &i }

// Redis分布式锁Lua脚本，只有锁的value和传入一致才删除
const unlockScript = `
if redis.call("get", KEYS[1]) == ARGV[1] then
  return redis.call("del", KEYS[1])
else
  return 0
end
`

func (s *SeckillOrderService) SeckillCreateOrder(ctx context.Context, userID int, activityDeviceID int, address string, payType string) error {
	lockKey := fmt.Sprintf("seckill:lock:%d:%d", activityDeviceID, userID)
	lockValue := uuid.New().String()
	// 1. 加锁（防止重复下单）
	ok, err := global.GVA_REDIS.SetNX(ctx, lockKey, lockValue, 5*time.Second).Result()
	if err != nil {
		return err
	}
	if !ok {
		return errors.New("请勿重复下单")
	}
	defer func() {
		// 用Lua脚本安全释放锁
		global.GVA_REDIS.Eval(ctx, unlockScript, []string{lockKey}, lockValue)
	}()

	// 2. 扣减Redis库存
	stockKey := fmt.Sprintf("seckill:stock:%d", activityDeviceID)
	stock, err := global.GVA_REDIS.LPop(ctx, stockKey).Result()
	if err != nil {
		return errors.New("库存不足或已售罄")
	}
	if stock == "" {
		return errors.New("库存不足")
	}

	// 3. 查询活动设备信息
	var activityDevice system.Seckill_activity_device
	if err := global.GVA_DB.Where("id = ?", activityDeviceID).First(&activityDevice).Error; err != nil {
		return errors.New("活动设备不存在")
	}
	// 4. 生成订单
	order := system.SeckillOrder{
		Order_sn:              ptrString(uuid.New().String()),
		User_id:               &userID,
		Decimal_device_id:     activityDevice.Seckill_decimal_device_id,
		Number:                ptrInt(1),
		Amount:                ptrInt(int(*activityDevice.Seckill_price)), // 如需金额*100请调整
		Pay_type:              ptrString("1"),
		Seckill_order_status:  ptrString("1"),
		Seckill_order_address: &address,
		Seckill_price:         activityDevice.Seckill_price,
		Seckill_activity_id:   activityDevice.Seckill_activity_id,
	}
	if err := global.GVA_DB.Create(&order).Error; err != nil {
		return errors.New("订单创建失败")
	}
	return nil
}
